﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Globalization;

namespace Gmantis.Controls
{
    [TemplatePart(Name = "HeaderPresenter", Type = typeof(ContentPresenter)), TemplateVisualState(Name = "Normal", GroupName = "CommonStates"), TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates"), TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")]
    public class HeaderedContentControl : ContentControl
    {
        // Fields
        protected internal ContentPresenter _elementHeaderPresenter;
        private bool _throwIsMouseOverChanged;
        internal static readonly DependencyProperty ForceMouseOverProperty = DependencyProperty.Register("ForceMouseOver", typeof(bool), typeof(HeaderedContentControl), new PropertyMetadata(new PropertyChangedCallback(HeaderedContentControl.OnForceMouseOverPropertyChanged)));
        public static readonly DependencyProperty HeaderBackgroundProperty = DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HeaderFontFamilyProperty = DependencyProperty.Register("HeaderFontFamily", typeof(FontFamily), typeof(HeaderedContentControl), new PropertyMetadata(new FontFamily("Portable User Interface")));
        public static readonly DependencyProperty HeaderFontSizeProperty = DependencyProperty.Register("HeaderFontSize", typeof(double), typeof(HeaderedContentControl), new PropertyMetadata(11.0));
        public static readonly DependencyProperty HeaderFontStretchProperty = DependencyProperty.Register("HeaderFontStretch", typeof(FontStretch), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HeaderFontStyleProperty = DependencyProperty.Register("HeaderFontStyle", typeof(FontStyle), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HeaderFontWeightProperty = DependencyProperty.Register("HeaderFontWeight", typeof(FontWeight), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HeaderForegroundProperty = DependencyProperty.Register("HeaderForeground", typeof(Brush), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HeaderPaddingProperty = DependencyProperty.Register("HeaderPadding", typeof(Thickness), typeof(HeaderedContentControl), null);
        internal const string HeaderPresenterElementName = "HeaderPresenter";
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(HeaderedContentControl), new PropertyMetadata(new PropertyChangedCallback(HeaderedContentControl.OnHeaderPropertyChanged)));
        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(HeaderedContentControl), null);
        public static readonly DependencyProperty HorizontalHeaderAlignmentProperty = DependencyProperty.Register("HorizontalHeaderAlignment", typeof(HorizontalAlignment), typeof(HeaderedContentControl), new PropertyMetadata(HorizontalAlignment.Stretch));
        public static readonly DependencyProperty IsMouseOverProperty = DependencyProperty.Register("IsMouseOver", typeof(bool), typeof(HeaderedContentControl), new PropertyMetadata(new PropertyChangedCallback(HeaderedContentControl.OnIsMouseOverPropertyChanged)));
        public static readonly DependencyProperty VerticalHeaderAlignmentProperty = DependencyProperty.Register("VerticalHeaderAlignment", typeof(VerticalAlignment), typeof(HeaderedContentControl), new PropertyMetadata(VerticalAlignment.Stretch));

        // Events
        public event EventHandler<PropertyChangedEventArgs<bool>> IsMouseOverChanged;

        // Methods
        public HeaderedContentControl()
        {
            RoutedEventHandler handler = null;
            DependencyPropertyChangedEventHandler handler2 = null;
            this._throwIsMouseOverChanged = true;
            base.DefaultStyleKey = typeof(HeaderedContentControl);
            if (handler == null)
            {
                handler = (param0, param1) => this.ChangeVisualStateCommon(false);
            }
            base.Loaded += handler;
            if (handler2 == null)
            {
                handler2 = (s, a) => this.ChangeVisualStateCommon(true);
            }
            base.IsEnabledChanged += handler2;
            base.MouseEnter += new MouseEventHandler(this.Control_MouseEnter);
            base.MouseLeave += new MouseEventHandler(this.Control_MouseLeave);
            this.SetCustomDefaultValues();
        }

        private void Control_MouseEnter(object sender, MouseEventArgs e)
        {
            if (InputEventArgs.GetPointerType(e) == PointerDeviceType.Mouse)
            {
                this.IsMouseOver = true;
            }
        }

        private void Control_MouseLeave(object sender, MouseEventArgs e)
        {
            if (InputEventArgs.GetPointerType(e) == PointerDeviceType.Mouse)
            {
                this.IsMouseOver = false;
            }
        }

        protected void ChangeVisualStateCommon(bool useTransitions)
        {
            if (!base.IsEnabled)
            {
                VisualStateHelper.GoToState(this, "Disabled", useTransitions);
            }
            if (base.IsEnabled)
            {
                VisualStateHelper.GoToState(this, "MouseOver", useTransitions);
            }
            if ((base.IsEnabled && !this.IsMouseOver) && !this.ForceMouseOver)
            {
                VisualStateHelper.GoToState(this, "Normal", useTransitions);
            }
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        private void InitializeHeaderPresenterPart()
        {
            this._elementHeaderPresenter.Content = this.Header;
        }

        public override void OnApplyTemplate()
        {
            this.OnBeforeApplyTemplate();
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._elementHeaderPresenter = this.GetTemplateChild<ContentPresenter>("HeaderPresenter", false, ref errors);
            if (this._elementHeaderPresenter != null)
            {
                this.InitializeHeaderPresenterPart();
            }
            if (!string.IsNullOrEmpty(errors))
            {
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to HeaderedContentControl.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.ChangeVisualStateCommon(false);
            }
        }

        private void OnBeforeApplyTemplate()
        {
            if (this._elementHeaderPresenter != null)
            {
                this._elementHeaderPresenter.Content = null;
            }
        }

        private static void OnForceMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as HeaderedContentControl).ChangeVisualStateCommon(true);
        }

        private void OnHeaderChanged(object oldValue)
        {
            if (this._elementHeaderPresenter != null)
            {
                this._elementHeaderPresenter.Content = this.Header;
            }
        }

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HeaderedContentControl control = d as HeaderedContentControl;
            object oldValue = e.OldValue;
            control.OnHeaderChanged(oldValue);
        }

        private static void OnIsMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HeaderedContentControl sender = d as HeaderedContentControl;
            if ((sender.IsMouseOverChanged != null) && sender._throwIsMouseOverChanged)
            {
                PropertyChangedEventArgs<bool> args = new PropertyChangedEventArgs<bool>
                {
                    OldValue = (bool)e.OldValue,
                    NewValue = (bool)e.NewValue
                };
                sender.IsMouseOverChanged(sender, args);
            }
            sender.ChangeVisualStateCommon(true);
        }

        private void SetCustomDefaultValues()
        {
            base.IsTabStop = false;
            base.IsEnabled = true;
        }

        // Properties
        internal bool ForceMouseOver
        {
            get
            {
                return (bool)base.GetValue(ForceMouseOverProperty);
            }
            set
            {
                base.SetValue(ForceMouseOverProperty, value);
            }
        }

        public object Header
        {
            get
            {
                return base.GetValue(HeaderProperty);
            }
            set
            {
                base.SetValue(HeaderProperty, value);
            }
        }

        public Brush HeaderBackground
        {
            get
            {
                return (Brush)base.GetValue(HeaderBackgroundProperty);
            }
            set
            {
                base.SetValue(HeaderBackgroundProperty, value);
            }
        }

        public FontFamily HeaderFontFamily
        {
            get
            {
                return (FontFamily)base.GetValue(HeaderFontFamilyProperty);
            }
            set
            {
                base.SetValue(HeaderFontFamilyProperty, value);
            }
        }

        public double HeaderFontSize
        {
            get
            {
                return (double)base.GetValue(HeaderFontSizeProperty);
            }
            set
            {
                base.SetValue(HeaderFontSizeProperty, value);
            }
        }

        public FontStretch HeaderFontStretch
        {
            get
            {
                return (FontStretch)base.GetValue(HeaderFontStretchProperty);
            }
            set
            {
                base.SetValue(HeaderFontStretchProperty, value);
            }
        }

        public FontStyle HeaderFontStyle
        {
            get
            {
                return (FontStyle)base.GetValue(HeaderFontStyleProperty);
            }
            set
            {
                base.SetValue(HeaderFontStyleProperty, value);
            }
        }

        public FontWeight HeaderFontWeight
        {
            get
            {
                return (FontWeight)base.GetValue(HeaderFontWeightProperty);
            }
            set
            {
                base.SetValue(HeaderFontWeightProperty, value);
            }
        }

        public Brush HeaderForeground
        {
            get
            {
                return (Brush)base.GetValue(HeaderForegroundProperty);
            }
            set
            {
                base.SetValue(HeaderForegroundProperty, value);
            }
        }

        public Thickness HeaderPadding
        {
            get
            {
                return (Thickness)base.GetValue(HeaderPaddingProperty);
            }
            set
            {
                base.SetValue(HeaderPaddingProperty, value);
            }
        }

        public DataTemplate HeaderTemplate
        {
            get
            {
                return (DataTemplate)base.GetValue(HeaderTemplateProperty);
            }
            set
            {
                base.SetValue(HeaderTemplateProperty, value);
            }
        }

        public HorizontalAlignment HorizontalHeaderAlignment
        {
            get
            {
                return (HorizontalAlignment)base.GetValue(HorizontalHeaderAlignmentProperty);
            }
            set
            {
                base.SetValue(HorizontalHeaderAlignmentProperty, value);
            }
        }

        public bool IsMouseOver
        {
            get
            {
                return (bool)base.GetValue(IsMouseOverProperty);
            }
            internal set
            {
                base.SetValue(IsMouseOverProperty, value);
            }
        }

        public VerticalAlignment VerticalHeaderAlignment
        {
            get
            {
                return (VerticalAlignment)base.GetValue(VerticalHeaderAlignmentProperty);
            }
            set
            {
                base.SetValue(VerticalHeaderAlignmentProperty, value);
            }
        }
    }
}
